import os
import re
import fnmatch
from concurrent.futures import ProcessPoolExecutor
from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, 
                            QLabel, QLineEdit, QPushButton, QListWidget, QListWidgetItem, 
                            QFileDialog, QWidget, QProgressBar, QMessageBox,
                            QFrame, QCheckBox)
from PyQt6.QtCore import QThread, pyqtSignal, Qt
from PyQt6.QtGui import QIcon, QFont, QPalette, QColor

class SearchThread(QThread):
    update_signal = pyqtSignal(str)
    finished_signal = pyqtSignal(list)
    progress_signal = pyqtSignal(int)

    def __init__(self, directory, pattern, use_regex, initial_results=None):
        super().__init__()
        self.directory = directory
        self.pattern = pattern
        self.use_regex = use_regex
        self.initial_results = initial_results
        self._is_running = True

    def run(self):
        matches = []
        try:
            if self.initial_results:
                # 在已有结果中搜索
                total = len(self.initial_results)
                current = 0
                
                for filepath in self.initial_results:
                    if not self._is_running:
                        return
                    
                    filename = os.path.basename(filepath)
                    try:
                        if self.use_regex:
                            if re.search(self.pattern, filename):
                                matches.append(filepath)
                                self.update_signal.emit(filepath)
                        else:
                            if fnmatch.fnmatch(filename, f'*{self.pattern}*'):
                                matches.append(filepath)
                                self.update_signal.emit(filepath)
                    except re.error:
                        pass
                    
                    current += 1
                    progress = int((current / total) * 100)
                    self.progress_signal.emit(progress)
            else:
                # 全新搜索
                total = 0
                for root, dirs, files in os.walk(self.directory):
                    if not self._is_running:
                        return
                    total += 1

                current = 0
                with ProcessPoolExecutor() as executor:
                    futures = []
                    for root, dirnames, filenames in os.walk(self.directory):
                        if not self._is_running:
                            return
                        futures.append(executor.submit(find_files_in_directory, root, self.pattern, self.use_regex))
                        current += 1
                        progress = int((current / total) * 100)
                        self.progress_signal.emit(progress)
                    
                    for future in futures:
                        if not self._is_running:
                            return
                        result = future.result()
                        for file in result:
                            matches.append(file)
                            self.update_signal.emit(file)
        except Exception as e:
            self.update_signal.emit(f"搜索过程中出现错误: {e}")
        
        self.finished_signal.emit(matches)

    def stop(self):
        self._is_running = False

def find_files_in_directory(root, pattern, use_regex):
    matches = []
    try:
        for filename in os.listdir(root):
            try:
                if use_regex:
                    if re.search(pattern, filename):
                        matches.append(os.path.join(root, filename))
                else:
                    if fnmatch.fnmatch(filename, f'*{pattern}*'):
                        matches.append(os.path.join(root, filename))
            except re.error:
                pass
    except PermissionError:
        pass
    except Exception as e:
        pass
    return matches

class FileSearchApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("高级文件搜索删除工具")
        self.setGeometry(100, 100, 900, 700)
        
        try:
            self.setWindowIcon(QIcon("search_icon.png"))
        except:
            pass
        
        self.search_thread = None
        self.results = []
        self.current_search_results = []  # 保存当前搜索结果
        self.init_ui()
        self.apply_styles()
        
    def init_ui(self):
        main_widget = QWidget()
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(20, 20, 20, 20)
        main_layout.setSpacing(15)
        
        title_label = QLabel("高级文件搜索删除工具 ")
        title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        title_font = QFont()
        title_font.setPointSize(18)
        title_font.setBold(True)
        title_label.setFont(title_font)
        
        separator = QFrame()
        separator.setFrameShape(QFrame.Shape.HLine)
        separator.setFrameShadow(QFrame.Shadow.Sunken)
        
        # 目录选择部分
        dir_frame = QFrame()
        dir_frame.setFrameShape(QFrame.Shape.StyledPanel)
        dir_frame.setFrameShadow(QFrame.Shadow.Raised)
        dir_layout = QHBoxLayout(dir_frame)
        dir_layout.setContentsMargins(15, 10, 15, 10)
        
        dir_label = QLabel("搜索目录:")
        dir_label.setFixedWidth(80)
        self.dir_input = QLineEdit()
        self.dir_input.setPlaceholderText("请选择或输入要搜索的目录")
        dir_button = QPushButton("浏览...")
        dir_button.setFixedWidth(80)
        dir_button.clicked.connect(self.browse_directory)
        dir_layout.addWidget(dir_label)
        dir_layout.addWidget(self.dir_input)
        dir_layout.addWidget(dir_button)
        
        # 关键词部分
        keyword_frame = QFrame()
        keyword_frame.setFrameShape(QFrame.Shape.StyledPanel)
        keyword_frame.setFrameShadow(QFrame.Shadow.Raised)
        keyword_layout = QVBoxLayout(keyword_frame)
        keyword_layout.setContentsMargins(15, 10, 15, 10)
        
        # 第一行：关键词输入
        keyword_row1 = QHBoxLayout()
        keyword_row1.setContentsMargins(0, 0, 0, 0)
        keyword_label = QLabel("搜索模式:")
        keyword_label.setFixedWidth(80)
        self.keyword_input = QLineEdit()
        self.keyword_input.setPlaceholderText("输入要搜索的文件名模式 (支持通配符*)")
        
        paste_button = QPushButton("粘贴")
        paste_button.setFixedWidth(60)
        paste_button.clicked.connect(self.paste_from_clipboard)
        
        keyword_row1.addWidget(keyword_label)
        keyword_row1.addWidget(self.keyword_input)
        keyword_row1.addWidget(paste_button)
        
        # 第二行：选项
        keyword_row2 = QHBoxLayout()
        keyword_row2.setContentsMargins(0, 10, 0, 0)
        
        self.regex_checkbox = QCheckBox("使用正则表达式")
        self.regex_checkbox.setToolTip("选中此项将使用正则表达式进行匹配")
        self.regex_checkbox.stateChanged.connect(self.update_placeholder_text)
        
        self.search_in_results_checkbox = QCheckBox("在结果中搜索")
        self.search_in_results_checkbox.setToolTip("在当前搜索结果基础上进行二次搜索")
        self.search_in_results_checkbox.setEnabled(False)  # 初始不可用
        
        keyword_row2.addWidget(self.regex_checkbox)
        keyword_row2.addWidget(self.search_in_results_checkbox)
        keyword_row2.addStretch()
        
        keyword_layout.addLayout(keyword_row1)
        keyword_layout.addLayout(keyword_row2)
        
        # 按钮部分
        button_frame = QFrame()
        button_layout = QHBoxLayout(button_frame)
        button_layout.setContentsMargins(0, 0, 0, 0)
        
        self.search_button = QPushButton("开始搜索")
        self.search_button.setIcon(QIcon.fromTheme("system-search"))
        self.search_button.clicked.connect(self.start_search)
        self.search_button.setFixedHeight(40)
        
        self.stop_button = QPushButton("停止搜索")
        self.stop_button.setIcon(QIcon.fromTheme("process-stop"))
        self.stop_button.clicked.connect(self.stop_search)
        self.stop_button.setFixedHeight(40)
        self.stop_button.setEnabled(False)
        
        button_layout.addWidget(self.search_button)
        button_layout.addWidget(self.stop_button)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        self.progress_bar.setTextVisible(True)
        self.progress_bar.setFixedHeight(20)
        
        # 结果显示
        result_frame = QFrame()
        result_frame.setFrameShape(QFrame.Shape.StyledPanel)
        result_frame.setFrameShadow(QFrame.Shadow.Raised)
        result_layout = QVBoxLayout(result_frame)
        result_layout.setContentsMargins(10, 10, 10, 10)
        
        result_label = QLabel("搜索结果:")
        result_label.setFont(QFont("Arial", 10, QFont.Weight.Bold))
        
        self.result_display = QListWidget()
        self.result_display.setAlternatingRowColors(True)
        self.result_display.setSpacing(5)
        self.result_display.setSelectionMode(QListWidget.SelectionMode.MultiSelection)  # 支持多选
        
        result_layout.addWidget(result_label)
        result_layout.addWidget(self.result_display)
        
        # 操作按钮
        button_row = QHBoxLayout()
        
        self.save_button = QPushButton("保存结果")
        self.save_button.setIcon(QIcon.fromTheme("document-save"))
        self.save_button.clicked.connect(self.save_results)
        self.save_button.setEnabled(False)
        self.save_button.setFixedHeight(40)
        
        self.clear_button = QPushButton("清除结果")
        self.clear_button.setIcon(QIcon.fromTheme("edit-clear"))
        self.clear_button.clicked.connect(self.clear_results)
        self.clear_button.setEnabled(False)
        self.clear_button.setFixedHeight(40)
        
        self.delete_selected_button = QPushButton("删除选中文件")
        self.delete_selected_button.setIcon(QIcon.fromTheme("edit-delete"))
        self.delete_selected_button.clicked.connect(self.delete_selected_files)
        self.delete_selected_button.setEnabled(False)
        self.delete_selected_button.setFixedHeight(40)
        
        self.delete_all_button = QPushButton("删除全部文件")
        self.delete_all_button.setIcon(QIcon.fromTheme("edit-delete"))
        self.delete_all_button.clicked.connect(self.delete_all_files)
        self.delete_all_button.setEnabled(False)
        self.delete_all_button.setFixedHeight(40)
        
        button_row.addWidget(self.save_button)
        button_row.addWidget(self.clear_button)
        button_row.addWidget(self.delete_selected_button)
        button_row.addWidget(self.delete_all_button)
        
        # 添加到主布局
        main_layout.addWidget(title_label)
        main_layout.addWidget(separator)
        main_layout.addWidget(dir_frame)
        main_layout.addWidget(keyword_frame)
        main_layout.addWidget(button_frame)
        main_layout.addWidget(self.progress_bar)
        main_layout.addWidget(result_frame)
        main_layout.addLayout(button_row)
        
        main_widget.setLayout(main_layout)
        self.setCentralWidget(main_widget)
        
    def paste_from_clipboard(self):
        clipboard = QApplication.clipboard()
        text = clipboard.text()
        if text:
            self.keyword_input.setText(text)
        
    def update_placeholder_text(self):
        if self.regex_checkbox.isChecked():
            self.keyword_input.setPlaceholderText(r"输入正则表达式模式 (例如: .*\.txt$ 匹配所有txt文件)")
        else:
            self.keyword_input.setPlaceholderText("输入要搜索的文件名模式 (支持通配符*)")
        
    def apply_styles(self):
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f5f5f5;
            }
            QFrame {
                background-color: white;
                border-radius: 5px;
            }
            QLabel {
                color: #333333;
            }
            QLineEdit {
                border: 1px solid #cccccc;
                border-radius: 3px;
                padding: 5px;
            }
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                border-radius: 5px;
                padding: 8px 15px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:disabled {
                background-color: #cccccc;
            }
            QPushButton#stop_button {
                background-color: #f44336;
            }
            QPushButton#stop_button:hover {
                background-color: #d32f2f;
            }
            QListWidget {
                border: 1px solid #cccccc;
                border-radius: 3px;
                font-family: Consolas, monospace;
            }
            QProgressBar {
                border: 1px solid #cccccc;
                border-radius: 5px;
                text-align: center;
            }
            QProgressBar::chunk {
                background-color: #4CAF50;
                width: 10px;
            }
            QCheckBox {
                spacing: 5px;
            }
        """)
        
        self.stop_button.setObjectName("stop_button")
        
        palette = self.palette()
        palette.setColor(QPalette.ColorRole.Window, QColor(245, 245, 245))
        palette.setColor(QPalette.ColorRole.WindowText, QColor(51, 51, 51))
        palette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.AlternateBase, QColor(240, 240, 240))
        palette.setColor(QPalette.ColorRole.ToolTipBase, QColor(255, 255, 220))
        palette.setColor(QPalette.ColorRole.ToolTipText, QColor(0, 0, 0))
        palette.setColor(QPalette.ColorRole.Text, QColor(0, 0, 0))
        palette.setColor(QPalette.ColorRole.Button, QColor(240, 240, 240))
        palette.setColor(QPalette.ColorRole.ButtonText, QColor(0, 0, 0))
        palette.setColor(QPalette.ColorRole.BrightText, QColor(255, 0, 0))
        palette.setColor(QPalette.ColorRole.Highlight, QColor(76, 175, 80))
        palette.setColor(QPalette.ColorRole.HighlightedText, QColor(255, 255, 255))
        self.setPalette(palette)
        
    def browse_directory(self):
        directory = QFileDialog.getExistingDirectory(self, "选择搜索目录")
        if directory:
            self.dir_input.setText(directory)
            
    def validate_regex(self, pattern):
        """验证正则表达式是否有效"""
        try:
            re.compile(pattern)
            return True
        except re.error as e:
            QMessageBox.warning(self, "正则表达式错误", 
                              f"无效的正则表达式: {str(e)}\n"
                              "请检查并修正您的正则表达式。")
            return False
            
    def start_search(self):
        directory = self.dir_input.text()
        pattern = self.keyword_input.text()
        use_regex = self.regex_checkbox.isChecked()
        search_in_results = self.search_in_results_checkbox.isChecked()
        
        if not pattern:
            QMessageBox.warning(self, "警告", "请输入搜索模式！")
            return
            
        # 如果使用正则表达式，先验证其有效性
        if use_regex and not self.validate_regex(pattern):
            return
            
        if search_in_results:
            if not self.current_search_results:
                QMessageBox.warning(self, "警告", "没有可用的搜索结果！")
                self.search_in_results_checkbox.setChecked(False)  # 自动取消选中
                return
        else:
            if not directory or not os.path.isdir(directory):
                QMessageBox.warning(self, "警告", "请输入有效的目录路径！")
                return
        
        self.result_display.clear()
        self.progress_bar.setValue(0)
        self.search_button.setEnabled(False)
        self.stop_button.setEnabled(True)
        self.save_button.setEnabled(False)
        self.clear_button.setEnabled(False)
        self.delete_selected_button.setEnabled(False)
        self.delete_all_button.setEnabled(False)
        self.results = []  # 清空结果列表
        
        initial_results = self.current_search_results if search_in_results else None
        self.search_thread = SearchThread(directory, pattern, use_regex, initial_results)
        self.search_thread.update_signal.connect(self.update_result_display)
        self.search_thread.finished_signal.connect(self.search_finished)
        self.search_thread.progress_signal.connect(self.update_progress)
        self.search_thread.start()
        
    def stop_search(self):
        if self.search_thread and self.search_thread.isRunning():
            self.search_thread.stop()
            self.search_thread.wait()
            self.result_display.addItem("搜索已停止")
            self.search_button.setEnabled(True)
            self.stop_button.setEnabled(False)
            self.save_button.setEnabled(True if self.results else False)
            self.clear_button.setEnabled(True if self.results else False)
            self.delete_selected_button.setEnabled(True if self.results else False)
            self.delete_all_button.setEnabled(True if self.results else False)
            
    def update_result_display(self, text):
        item = QListWidgetItem(text)
        self.result_display.addItem(item)
        
    def update_progress(self, value):
        self.progress_bar.setValue(value)
        
    def search_finished(self, results):
        self.current_search_results = results  # 保存当前搜索结果
        self.search_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        self.save_button.setEnabled(True if results else False)
        self.clear_button.setEnabled(True if results else False)
        self.delete_selected_button.setEnabled(True if results else False)
        self.delete_all_button.setEnabled(True if results else False)
        self.search_in_results_checkbox.setEnabled(True if results else False)
        self.results = results  # 保存完整结果列表
        
        if results:
            self.result_display.addItem(f"\n搜索完成，共找到 {len(results)} 个文件。")
        else:
            self.result_display.addItem("\n未找到匹配的文件。")
            # 如果没有找到结果，自动取消"在结果中搜索"选项
            self.search_in_results_checkbox.setChecked(False)
            
    def save_results(self):
        if not self.results:
            QMessageBox.warning(self, "警告", "没有可保存的结果！")
            return
            
        directory = self.dir_input.text()
        last_dir_name = os.path.basename(directory.rstrip('/\\'))
        if not last_dir_name:
            last_dir_name = os.path.splitdrive(directory)[0].replace(':', '') + '_root'
        
        pattern = self.keyword_input.text()
        default_filename = f"search_results_in_{last_dir_name}.txt"
        desktop_path = os.path.join(os.path.expanduser('~'), 'Desktop')
        default_path = os.path.join(desktop_path, default_filename)
        
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存结果", default_path, "文本文件 (*.txt);;所有文件 (*)"
        )
        
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(f"搜索目录: {directory}\n")
                    f.write(f"搜索模式: {pattern}\n")
                    f.write(f"使用正则表达式: {'是' if self.regex_checkbox.isChecked() else '否'}\n")
                    f.write(f"在结果中搜索: {'是' if self.search_in_results_checkbox.isChecked() else '否'}\n")
                    f.write(f"找到 {len(self.results)} 个文件:\n\n")
                    f.write('\n'.join(self.results))
                QMessageBox.information(self, "成功", f"结果已成功保存到:\n{file_path}")
            except Exception as e:
                QMessageBox.critical(self, "错误", f"保存文件时出错: {str(e)}")
    
    def clear_results(self):
        self.result_display.clear()
        self.results = []
        self.current_search_results = []
        self.save_button.setEnabled(False)
        self.clear_button.setEnabled(False)
        self.delete_selected_button.setEnabled(False)
        self.delete_all_button.setEnabled(False)
        self.search_in_results_checkbox.setEnabled(False)
        self.search_in_results_checkbox.setChecked(False)  # 清除时取消选中
        self.progress_bar.setValue(0)

    def delete_selected_files(self):
        selected_items = self.result_display.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "警告", "没有选中任何文件！")
            return

        reply = QMessageBox.question(self, "确认删除", "确定要删除选中的文件吗？此操作无法撤销！",
                                     QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
        if reply == QMessageBox.StandardButton.No:
            return

        for item in selected_items:
            file_path = item.text()
            try:
                os.remove(file_path)
                self.result_display.takeItem(self.result_display.row(item))
                self.results.remove(file_path)
            except Exception as e:
                QMessageBox.critical(self, "删除失败", f"无法删除文件 {file_path}：{str(e)}")

        self.update_buttons_state()

    def delete_all_files(self):
        if not self.results:
            QMessageBox.warning(self, "警告", "没有可删除的文件！")
            return

        reply = QMessageBox.question(self, "确认删除", "确定要删除所有搜索结果中的文件吗？此操作无法撤销！",
                                     QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
        if reply == QMessageBox.StandardButton.No:
            return

        for file_path in self.results:
            try:
                os.remove(file_path)
            except Exception as e:
                QMessageBox.critical(self, "删除失败", f"无法删除文件 {file_path}：{str(e)}")
                break

        self.result_display.clear()
        self.results = []
        self.current_search_results = []
        self.update_buttons_state()

    def update_buttons_state(self):
        self.save_button.setEnabled(bool(self.results))
        self.clear_button.setEnabled(bool(self.results))
        self.delete_selected_button.setEnabled(bool(self.results))
        self.delete_all_button.setEnabled(bool(self.results))
        self.search_in_results_checkbox.setEnabled(bool(self.results))

if __name__ == "__main__":
    app = QApplication([])
    app.setStyle("Fusion")
    window = FileSearchApp()
    window.show()
    app.exec()